package com.bapoint.springsecurity.config;

import com.alibaba.fastjson.JSON;
import com.bapoint.springsecurity.filter.JwtAuthenticationTokenFilter;
import com.bapoint.springsecurity.filter.VerificationCodeFilter;
import com.bapoint.springsecurity.utils.JwtUtils;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.log4j.Log4j;
import lombok.extern.log4j.Log4j2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.csrf.LazyCsrfTokenRepository;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static org.springframework.security.config.Customizer.withDefaults;

/**
 * @ClassName SpringSecurity
 * @Description TODO
 * @Author 王逸攀
 * @Date 2024/3/6 20:27
 * @Version 1.0
 */

@Configuration
@EnableWebSecurity
@Log4j2
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        //authorizeHttpRequests:针对http请求进行授权配置
        //login登录接口需要匿名访问
        //permitAll:具有所有权限 也就可以匿名可以访问
        //anyRequest:任何请求 所有请求
        //authenticated:认证【登录】
        http.authorizeHttpRequests(authorizeHttpRequests ->
                authorizeHttpRequests
                        .requestMatchers("/admin/api").hasAuthority("admin:api")
                        .requestMatchers("/user/api").hasAnyAuthority("admin:api","user:api")



                        .requestMatchers("/app/api").permitAll()
                        .requestMatchers("/app/apiap/**").permitAll()
                        .requestMatchers("/login").permitAll()
                        .requestMatchers("/logout").permitAll()
                        .anyRequest().authenticated()

        );
        http.addFilterBefore(new VerificationCodeFilter(), UsernamePasswordAuthenticationFilter.class);
        http.addFilterAfter(new JwtAuthenticationTokenFilter(), VerificationCodeFilter.class);
        //        http.addFilterAt(loginAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        //http:后面可以一直点 但是太多内容之后不美观
        //loginProcessingUrl:指定登录接口
        //successHandler:登录成功处理器
        //failureHandler:登录失败处理器
        //自定义登录接口
        http.formLogin(formLogin ->
                formLogin
                        .loginProcessingUrl("/login").permitAll()
                        .successHandler(new AuthenticationSuccessHandler() {
                            @Override
                            public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                                response.setContentType("text/html;charset=UTF-8");
//                                response.getWriter().write("loginOk");
                                log.info("MyLoginSuccessHandler.onAuthenticationSuccess->登录成功");

                                String token = JwtUtils.token(authentication);
                                response.addHeader("token", token);

                                response.setContentType("application/json;charset=UTF-8");
                                Map<String, Object> tokenInfo = new HashMap<>();
                                tokenInfo.put("token",token);
                                response.getWriter().write(JSON.toJSONString(tokenInfo));
                            }
                        })
                        .failureHandler(new AuthenticationFailureHandler() {
                            @Override
                            public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
                                response.setContentType("text/html;charset=UTF-8");
                                response.getWriter().write(exception.getMessage());
                                System.out.println(request.getMethod());
                                System.out.println(request.getParameter("data"));
                                System.out.println(request.getAttribute("password"));
                                System.out.println("登录异常信息");
                                exception.printStackTrace();
                            }
                        })
        );


        http.exceptionHandling(e->e.accessDeniedHandler(new AccessDeniedHandler() {
            @Override
            public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                response.setContentType("text/html;charset=UTF-8");
                response.getWriter().write("权限不足");
            }
        }));

        //记住我功能
        http.rememberMe(e->e.rememberMeParameter("rememberMe").rememberMeCookieName("rememberMe").key("myKey"));


        //Customizer.withDefaults():关闭
        //http.csrf(Customizer.withDefaults());//跨域漏洞防御:关闭
        //http.csrf(e->e.disable());
        //http.csrf(crsf->crsf.disable());//相当于 http.csrf(Customizer.withDefaults());
        http.csrf(e->e.disable());//封装的太过于抽象比较难以阅读代码【装X】

        http.cors(e -> e.disable());//跨域拦截关闭

        http.logout(e->e.logoutUrl("/logout").logoutSuccessHandler(new LogoutSuccessHandler() {
            @Override
            public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                response.setContentType("text/html;charset=UTF-8");
                response.getWriter().write("logout success");
            }
        }));//退出登录

        return http.build();
    }

//    @Bean
//    public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
//        UserDetails user1 = User.withUsername("admin").password("123456").roles("admin","user").build();
//        UserDetails user2 = User.withUsername("user").password("123456").roles("user").build();
//        return new InMemoryUserDetailsManager(user1, user2);
//    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }


}
